load 'executor.rb'

class MarsVoyages
  
  #Print out the version of Adameus
  def version
    cur_version = Executor.version
    puts 'Version: ' + cur_version.to_s
    return cur_version.to_f
  end

  #Print out all the airlines
  def airlines
    puts 'Airlines:'
    airlines_map = Executor.airlines
    airlines_map.each_pair do |key_val|
      puts key_val[0] + " " + key_val[1]
    end
    puts
    return airlines_map
  end

  #Print out all the airports
  def airports
    puts 'Airports:'
    airports_map = Executor.airports 
    airports_map.each_pair do |key_val|  
      puts key_val[1].to_s
    end
    puts
    return airports_map
  end

  #Print out the possible destinations of a specific airport
  def destinations(airport)
    destinations_arr =  Executor.destinations(airport)
    puts 'Destinations from ' + airport + ':'
    destinations_arr.each do |val|
      puts val
    end
    puts
    return destinations_arr
  end 

  #Print out each possible connection from x to y on day z
  def connections(from, to, on)
    connections_arr = Executor.connections(from, to, on)
    puts 'Connections from ' + from + ' to ' + to + ' on ' + on + ":"
    connections_arr.each do |connection|
      puts connection.to_s
    end
    puts
    return connections_arr
  end

  #Print out, given a flight number, the two airports it connects
  def flight(flightnr)
    airport_arr = Executor.flight(flightnr)
    puts "Flight " + flightnr + " connects:"
    puts airport_arr[0].to_s + " and " + airport_arr[1].to_s
    puts
    return airport_arr
  end
  
  def available_seats(date, flightnr, cat)
    pr = Executor.pricing(date, flightnr, cat)
    puts "Available seats for " + flightnr.to_s + " on " + date.to_s + " for category " + cat + ": " + pr.seats.to_s + " seat(s)"
    puts
    return pr.seats
  end

  def max_available_seats(multi_flight, cat)
    max_available = 999999
    multi_flight.connections.each do |connection|
      a_seats = available_seats(connection.departure_date,connection.flightnr,cat)
      if(a_seats < max_available)
        max_available = a_seats
      end
    end
    puts "Max available seats for flight path: " + max_available.to_s + " seat(s)"
    puts
    return max_available
  end

  #Print out on what days of the week a given flightnumber flies
  def days_of_the_week(flightnr)
    days_ot_week = Executor.days_of_the_week(flightnr)
    puts "Flight " + flightnr + " flies on:"
    days_ot_week.each_pair do |key_val|
      puts key_val[0] + " " + (key_val[1] ? "Yes" : "No")
    end
    puts
    return days_ot_week
  end
  
  #Print out the cheapest possible ticket on a given day, for a certain from and to
  def cheapest_ticket_on_day(from,dest,date, cat)
    puts "Best priced ticket from "+ from + " to " + dest + " on " + date +" is: "
    cheapest_pricing = Pricing.new(1,999999)
    cheapest_con = ""    
    Executor.connections(from, dest, date).each do |value|
      flight = value.flightnr
      price_det = Executor.pricing(date, flight,cat)
      if price_det.price < cheapest_pricing.price && price_det.price != 0
         cheapest_pricing = price_det
         cheapest_con = value
      end
    end
    puts "flight: " + cheapest_con.to_s + "   price: " + cheapest_pricing.price.to_s 
    puts
    return cheapest_pricing
  end
  
  #Book a seat on a given flightnumber on a given date, for a specific person
  def book(date, flightnr, cat, gender, first_name, surname)
    booking_code = Executor.hold(date, flightnr, cat, gender, first_name, surname)
    result = Executor.book(booking_code)
    puts result.to_s
    puts
    return result
  end
    
  #Book a multi hop flight
  def book_multi(multi_hop, cat, gender, first_name, surname)
    booking_codes = Array.new
    multi_hop.connections.each do |connection|
      begin
        booking_code = Executor.hold(connection.departure_date, connection.flightnr, cat, gender, first_name, surname)
        booking_codes << booking_code
      rescue
        for bcode in booking_codes
          Executor.cancel(bcode)
        end
        raise
      end
    end
    bookings = Executor.book_codes(booking_codes)
    bookings.each { |booking| puts booking.to_s }
    puts
    return bookings
  end
  
  #Book a number of seats on a given flightnumber on a given date, for a specific group of persons
  def book_group(date, flightnr, cat, nbOfPeople, group_name)
    booking_codes = Array.new
    for i in (1..nbOfPeople)
      begin
        booking_code = Executor.hold(date, flightnr, cat, 'M', group_name, i.to_s)
        booking_codes << booking_code
      rescue
        for bcode in booking_codes
          Executor.cancel(bcode)
        end
        raise
      end
    end
    bookings = Executor.book_codes(booking_codes)
    gb = GroupBooking.new(bookings)
    puts gb.to_s
    puts
    return gb
  end
  
  #Cancel a booking
  def cancel(bookingnr)
    result = Executor.cancel(bookingnr)
    puts result
    return result
  end
  
  #Get the details of a certain booking
  def query_booking(bookingnr)
    result = Executor.query_booking(bookingnr)
    if !result.nil?
      puts "Booking Details:"
      puts result.to_s
      puts
      return result
    else
      puts "No such booking."
    end
    return nil
  end
  
  # @return Connection with shortest overall duration between two airports starting 
  # on a given date with a maximum of hops to be passed
  # => If there is a connection that takes less time but starts LATER, that flight MAY be chosen
  def flight_path(from,to,on_date,max_hops=3)
    multi_flights = Executor.multi_flight_connections(from, to, on_date, max_hops)
    shortest_flight = multi_flights.min { |x,y| x.duration.hour*60+x.duration.minute <=> y.duration.hour*60+y.duration.minute }
    if(shortest_flight === nil)
      puts "No path found"
    else
      puts shortest_flight.to_s
      shortest_flight.connections.each { |item| puts "Connection: " + item.to_s  }
      puts
    end
    return shortest_flight
  end  
  
  # @return Connection with shortest overall duration between two airports starting 
  # on a given date with a maximum of hops to be passed
  # => Connection that does not start on the given date will be IGNORED
  def strict_flight_path(from,to,on_date,max_hops=3)
    multi_flights = Executor.multi_flight_connections(from, to, on_date, max_hops)
    strict_date = Date.parse(on_date)
    multi_flights.delete_if { |m_f| m_f.departure_date.to_s != strict_date.to_s }
    shortest_flight = multi_flights.min { |x,y| x.duration.hour*60+x.duration.minute <=> y.duration.hour*60+y.duration.minute }
    if(shortest_flight === nil)
      puts "No path found"
    else
      puts shortest_flight.to_s
      shortest_flight.connections.each { |item| puts "Connection: " + item.to_s  }
      puts
    end
    return shortest_flight
  end
  
  def flight_paths_starting_from_dates(from,to,date_from,days_amount,max_hops=3)
    departure_date = Date.parse(date_from)
    flight_paths = Array.new
    for i in 0..days_amount-1
      #next_day is private so by doing this I can still use the next_day method.
      date_str = departure_date.send(:next_day, i).to_s
      flight_paths << strict_flight_path(from,to,date_str,max_hops)
    end
    return flight_paths
  end
  
  def quit
    exit
  end
end
